import numpy as np
from datetime import datetime, timedelta


class Monitor:
    def __init__(self, threshold):
        self.time_move = None
        self.one_pass_time = None
        self.threshold_dict = threshold
        # self.format_str = "%Y-%m-%d %H:%M:%S"
        self.event = {}
        self.event_time_list = []
        self.time_list = []
        self.time_duration_list = []
        self.score = 50
        self.num_flag = False
        self.duration_average = None
        self.one_frame_list = []
        self.empty_count = 0
        self.my_prev_time = 0

    def flow_change(self, data, last_data):
        flow_change_flag = 0
        # 流量变化较大
        flow = self.threshold_dict["flow"]
        up_flow = last_data["data"]["up_flow_num"] - data["data"]["up_flow_num"]
        down_flow = last_data["data"]["down_flow_num"] - data["data"]["down_flow_num"]
        # 不关注上游变化
        # if up_flow > flow * last_data["data"]["up_flow_num"]:
        #     flag = 1
        # 下游流量骤降
        if down_flow > flow * last_data["data"]["down_flow_num"]:
            flow_change_flag = 1
        # if up_flow > flow * last_data["data"]["up_flow_num"]:
        #     flow_change_flag = 0
        # 上下游流量差值
        flow_diff = max((data["data"]["up_flow_num"] - data["data"]["down_flow_num"]), 0)
        flow_diff_p = int(flow_diff / data["data"]["up_flow_num"] * 100) if data["data"]["up_flow_num"] != 0 else 100

        return flow_change_flag, flow_diff, flow_diff_p

    def car_speed(self, data, last_data, vtype="1"):
        speed_change_flag = 0
        # 小客车速度骤降
        speed = self.threshold_dict["speed"]
        if vtype not in data["data"]["type_speed_dict"].keys() or vtype not in last_data["data"]["type_speed_dict"].keys():
            return speed_change_flag, 0
        current_speed = data["data"]["type_speed_dict"][vtype]["mean_speed"]
        last_speed = last_data["data"]["type_speed_dict"][vtype]["mean_speed"]
        speed_diff = last_speed - current_speed
        if speed_diff > speed * last_speed and last_speed >= 60:
            speed_change_flag = 1
        speed_60_diff = max(int(60 - current_speed), 0)
        return speed_change_flag, speed_60_diff

    def car_slow_num(self, data, vtype="1"):
        # 小客车慢行数量过多
        # slow_num = self.threshold_dict["slow_num"]
        if vtype not in data["data"]["type_speed_dict"].keys():
            return 0
        num = data["data"]["type_speed_dict"][vtype]["slow_level_count"]
        current_slow_num = num[1] + num[2] + num[3]
        # if current_num >= slow_num:
        #     slow_num_flag = 1
        return current_slow_num

    def flow_empty(self, data):
        up_flow = data["data"]["up_flow_num"]
        down_flow = data["data"]["down_flow_num"]
        if up_flow == 0 and down_flow == 0:
            return True
        return False

    def pass_rate(self, data, vtype="1"):
        pass_rate = self.threshold_dict["pass_rate"]
        # if data["info"]["info"] == "10005":
        #     pass_rate = 30

        if vtype is None:
            pass_rate_dict = {"pass_num": 0, "all_count": 0}
            for vtype in data["data"]["type_pass_rate_dict"].keys():
                car_pass_rate = data["data"]["type_pass_rate_dict"][vtype]
                pass_rate_dict["pass_num"] += car_pass_rate["pass"]
                pass_rate_dict["all_count"] += car_pass_rate["count"]
            current_pass_rate = int(pass_rate_dict["pass_num"] / pass_rate_dict["all_count"] * 100)
            if current_pass_rate < pass_rate:
                return 1, current_pass_rate
            else:
                return 0, current_pass_rate

        if vtype not in data["data"]["type_pass_rate_dict"].keys():
            # 20250331-gj
            if len(self.time_list) > 20:
                last_flag_dict = self.event[self.time_list[-1]] if self.time_list[-1] in self.event.keys() else {}
                if last_flag_dict["block_flag"] == 1 and last_flag_dict["down_flow"] == 0:
                    return 0, last_flag_dict["current_pass_rate"]
                else:
                    return 0, 100
            return 0, 100
        car_pass_rate = data["data"]["type_pass_rate_dict"][vtype]

        current_pass_rate = int(car_pass_rate["pass"] / car_pass_rate["count"] * 100)
        if current_pass_rate < pass_rate:
            return 1, current_pass_rate
        return 0, current_pass_rate

    def interval_num(self, data):
        interval_num = int(data["info"]["dist"] * 1000 / 100.0 * data["info"]["lane_num"])
        interval_diff = max((data["data"]["interval_num"] - interval_num), 0)
        return interval_diff

    def duration_num(self, data):
        duration_num = 0
        mean_duration = 0
        if data["data"]["type_speed_dict"]:
            for vtype in data["data"]["type_speed_dict"].keys():
                duration_num += data["data"]["type_speed_dict"][vtype]["count"]
            if "1" in data["data"]["type_speed_dict"].keys():
                duration_mean_speed = data["data"]["type_speed_dict"]["1"]["mean_speed"]
                mean_duration = int(data["info"]["dist"] / duration_mean_speed * 3600)

        return duration_num, mean_duration

    def event_detection(self, event_time, data):
        if not self.time_list:
            last_flag_dict = {}
        else:
            last_flag_dict = self.event[self.time_list[-1]] if self.time_list[-1] in self.event.keys() else {}
        if self.event[event_time]["duration_num"] > 5:
            self.num_flag = True
        if last_flag_dict and self.num_flag:
            current_num = self.event[event_time]["duration_num"]
            last_num = last_flag_dict["duration_num"]
            last_score = last_flag_dict["block_probability"]
            if last_score < 50:
                if last_num > 20:
                    if current_num <= 5:
                        self.event[event_time]["block_probability"] = 60
                    else:
                        if len(self.one_frame_list) >= 3:
                            if self.one_frame_list[-1] <= 1 and self.one_frame_list[-2] <= 1 and self.one_frame_list[-3] <= 1:
                                self.event[event_time]["block_probability"] = 60
                else:
                    if current_num <= 3:
                        temp_list = []
                        if len(self.time_list) >= 40:
                            for i in range(1, 41):
                                sub_list = self.time_list[-i]  # 切片获取列表的最后 i 个元素
                                if self.event[sub_list]['duration_num'] <= 3:
                                    temp_list.append(True)
                                else:
                                    temp_list.append(False)
                        else:
                            for i in range(len(self.time_list)):
                                sub_list = self.time_list[-i]  # 切片获取列表的最后 i 个元素
                                if self.event[sub_list]['duration_num'] <= 3:
                                    temp_list.append(True)
                                else:
                                    temp_list.append(False)
                        if len(temp_list) > 0 and all(temp_list):
                            self.event[event_time]["block_probability"] = 60
                    if self.one_frame_list[-1] <= 1 and self.event[event_time]["block_probability"] != 60:
                        if len(self.one_frame_list) >= 2 and self.one_frame_list[-2] <= 1:
                            last_temp_list = []
                            if len(self.time_list) >= 30:
                                for i in range(1, 31):
                                    sub_list = self.time_list[-i]  # 切片获取列表的最后 i 个元素
                                    if self.event[sub_list]['duration_num'] >= 20:
                                        last_temp_list.append(False)
                                        break
                            else:
                                for i in range(len(self.time_list)):
                                    sub_list = self.time_list[-i]  # 切片获取列表的最后 i 个元素
                                    if self.event[sub_list]['duration_num'] >= 20:
                                        last_temp_list.append(False)
                                        break
                            if len(last_temp_list) > 0 and not all(last_temp_list):
                                self.event[event_time]["block_probability"] = 60

            else:
                if current_num <= 3 and self.one_frame_list[-1] <= 2:
                    self.event[event_time]["block_probability"] = 60
                # 该区间存在匝道导致车辆下行
                if data["info"]["is_fork"]:
                    if self.event[event_time]["current_pass_rate"] >= 20:
                        self.event[event_time]["block_probability"] = 10
                else:
                    if self.event[event_time]["current_pass_rate"] >= 30:
                        self.event[event_time]["block_probability"] = 10
                # if data["info"]["down_gantry_id"] in ["TLS_1_1", "TLS_3_1"]:
                #     if self.event[event_time]["current_pass_rate"] > 0:
                #         self.event[event_time]["block_probability"] = 10
                if last_flag_dict["block_probability"] == 60 and self.event[event_time]["block_probability"] == 60:
                    if self.event[event_time]["flow_diff"] >= 10 and self.event[event_time]["down_flow"] < 5:
                        # 上报阻断
                        self.event[event_time]["content"] = "阻断"
                        self.event[event_time]["block_flag"] = 1
                    # elif self.event[event_time]["flow_empty_flag"]:
                    #     # 上报阻断
                    #     self.event[event_time]["content"] = "阻断"
                    #     self.event[event_time]["block_flag"] = 1
                    # if data["info"]["down_gantry_id"] in ["TLS_1_1", "TLS_3_1"]:
                    #     if self.event[event_time]["flow_diff"] >= 20:
                    #         # 上报阻断
                    #         self.event[event_time]["content"] = "阻断"
                    #         self.event[event_time]["block_flag"] = 1
                    # else:
                    #     if self.event[event_time]["flow_diff"] >= 10:
                    #         # 上报阻断
                    #         self.event[event_time]["content"] = "阻断"
                    #         self.event[event_time]["block_flag"] = 1

        if last_flag_dict and self.event[event_time]["content"] != "阻断":
            duration_average = 0
            if len(self.time_duration_list) >= 50 and self.duration_average is None:
                self.duration_average = np.median(self.time_duration_list)

            if self.event[event_time]["block_probability"] < 50:
                if "1" in data["data"]["type_speed_dict"].keys():
                    current_speed = data["data"]["type_speed_dict"]["1"]["speed_list"]
                    filter_data = np.array(current_speed)
                    average_speed = np.median(filter_data)
                    average_duration = int(data["info"]["dist"] / average_speed * 3600)
                    if self.duration_average is None:
                        self.time_duration_list.append(average_duration)
                        duration_average = self.my_prev_time
                    else:
                        duration_average = self.my_prev_time * 0.8 + self.duration_average * 0.2

                    if len(self.one_frame_list) > 5 and self.one_frame_list[-2] == 0 and self.one_frame_list[-1] == 0:
                        self.event[event_time]["block_flag"] = 0
                    duration_value = round(average_duration / duration_average * 40)
                    self.event[event_time]["duration_value"] = duration_value
                    if 55 < duration_value <= 60:
                        if last_flag_dict["block_flag"]:
                            self.event[event_time]["block_probability"] = 51
                            self.event[event_time]["content"] = "车辆缓行"
                            self.event[event_time]["block_flag"] = 1
                        elif self.event[event_time]['duration_num'] >= 20:
                            self.event[event_time]["block_probability"] = 51
                            self.event[event_time]["content"] = "车辆缓行"
                    elif 60 < duration_value <= 100:
                        if last_flag_dict["block_flag"]:
                            self.event[event_time]["block_probability"] = 52
                            self.event[event_time]["content"] = "严重拥堵"
                            self.event[event_time]["block_flag"] = 1
                        elif self.event[event_time]['duration_num'] >= 20:
                            self.event[event_time]["block_probability"] = 52
                            self.event[event_time]["content"] = "严重拥堵"
                    elif duration_value > 100:
                        if last_flag_dict["block_flag"]:
                            self.event[event_time]["block_probability"] = 53
                            self.event[event_time]["content"] = "重度阻塞"
                            self.event[event_time]["block_flag"] = 1
                        elif self.event[event_time]['duration_num'] >= 20:
                            self.event[event_time]["block_probability"] = 53
                            self.event[event_time]["content"] = "重度阻塞"

    def clear_data(self):
        if self.time_list[-1] - self.time_list[0] > timedelta(hours=24):
            self.one_frame_list.pop(0)
            if self.time_list[0] in self.event.keys():
                self.event.pop(self.time_list[0])
            self.time_list.pop(0)

    def run(self, data, last_data):
        content = "畅通"
        self.one_pass_time = data["info"]["car_pass_time"]
        self.time_move = data["info"]["time_move"]
        self.my_prev_time = data["info"]["dist"] / 80 * 3600
        # 结束时间 datetime类型的时间数据
        event_time = data["data"]["time"]
        self.event[event_time] = {}
        if last_data is not None:
            try:
                # 流量变化标志flow_change_flag，0：正常，1：下游骤降, 上下游流量差值flow_diff
                flow_change_flag, flow_diff, flow_diff_p = self.flow_change(data, last_data)
                # speed_change_flag，0：正常，1：车速骤降，低于60的速度差值speed_60_diff
                speed_change_flag, speed_60_diff = self.car_speed(data, last_data)
                # 慢行车数量current_slow_num, 0：正常
                current_slow_num = self.car_slow_num(data)
                # 车流量为零标志flow_empty_flag，True：上下游车流量均为零，False：正常
                flow_empty_flag = self.flow_empty(data)
                # 通过率标志pass_flag，1：通过率过低，0：正常
                pass_flag, current_pass_rate = self.pass_rate(data)
                # 间隔内车数量标志interval_diff，0：正常
                interval_diff = self.interval_num(data)
                # print(data)
                duration_num, mean_duration = self.duration_num(data)
                # print("duration_num: ", duration_num)

                one_frame_num = len(list(data["data"]["type_pass_time_ture"].keys()))
                self.one_frame_list.append(one_frame_num)

                # if flow_empty_flag:
                #     self.empty_count += 1
                # else:
                #     self.empty_count = 0
                # if self.empty_count >= 10:
                #     self.num_flag = False

                self.event[event_time] = {
                    "up_flow": data["data"]["up_flow_num"],
                    "down_flow": data["data"]["down_flow_num"],
                    "flow_change_flag": flow_change_flag,
                    "flow_diff_p": flow_diff_p,
                    "flow_diff": flow_diff,
                    "speed_change_flag": speed_change_flag,
                    "speed_60_diff": speed_60_diff,
                    "current_slow_num": current_slow_num,
                    "flow_empty_flag": flow_empty_flag,
                    "pass_flag": pass_flag,
                    "current_pass_rate": current_pass_rate,
                    "interval_diff": data["data"]["interval_num"],
                    "duration_num": duration_num,
                    "duration_average": self.duration_average if self.duration_average is not None else 0,
                    "duration_value": 0,
                    "block_probability": 0,
                    "content": "畅通",
                    "one_frame_num": one_frame_num,
                    "block_flag": 0,
                }
                self.event_detection(event_time, data)
                content = self.event[event_time]["content"]
                self.time_list.append(event_time)

                self.clear_data()
            except Exception as e:
                print("error:", e)

        return content, self.event[event_time]


class PreviousCongestion:
    def __init__(self, define, config_data):
        self.congestion = "畅通"
        self.define = define
        self.speed_limit = config_data["SpeedLimit"]
        self.density_limit = config_data["DensityLimit"]
        self.level_num = int(config_data["congestion_level_num"])

    def run(self, data):
        lane_num = int(data["info"]["lane_num"])
        car_max_speed = data["info"]["car_max_speed"]
        if car_max_speed >= 60:
            car_max_speed_str = str(int(car_max_speed))
        else:
            car_max_speed_str = "50"
        if car_max_speed not in self.speed_limit.keys():
            car_max_speed_str = "80"
        car_speed_l0 = self.speed_limit[car_max_speed_str]["l0"]
        car_speed_l1 = self.speed_limit[car_max_speed_str]["l1"]
        car_speed_l2 = self.speed_limit[car_max_speed_str]["l2"]
        car_speed_l3 = self.speed_limit[car_max_speed_str]["l3"]
        mean_speed = 0
        pass_num = 0
        interval_vlp = 0
        # 结束时间 datetime类型的时间数据
        event_time = data["data"]["time"]
        window_length = data["info"]["time_interval"]
        if "1" not in data["data"]["type_speed_dict"].keys():
            mean_speed = 80
        else:
            mean_speed = data["data"]["type_speed_dict"]["1"]["mean_speed"]
        for vtype in data["data"]["type_speed_dict"].keys():
            pass_num += data["data"]["type_speed_dict"][vtype]["count"]
        interval_vlp_list = list(data["data"]["interval_dict"].keys())
        if len(interval_vlp_list) > 0:
            for i in range(len(interval_vlp_list) - 1, -1, -1):
                if data["data"]["interval_dict"][interval_vlp_list[i]][self.define["TIME"]] > (event_time-window_length):
                    interval_vlp += 1
                else:
                    break
        else:
            interval_vlp = 0

        average_density = int((pass_num + interval_vlp) * (3600 / window_length.total_seconds()) / mean_speed) if mean_speed > 0 else 0
        # if mean_speed >= car_speed_l1 or average_density <= (20 * int(data["info"]["lane_num"])) or interval_vlp <= 20 * data["info"]["dist"]:

        if mean_speed >= car_speed_l1 or average_density <= (20 * lane_num):
            self.congestion = "畅通"
        elif mean_speed >= car_speed_l2:
            self.congestion = "轻度拥堵"
        elif mean_speed >= car_speed_l3:
            self.congestion = "中度拥堵"
        else:
            self.congestion = "严重拥堵"

        if self.congestion == "畅通" and self.level_num == 5 and mean_speed < car_speed_l0 and average_density > (20 * lane_num):
            self.congestion = "缓行"
        elif self.congestion == "轻度拥堵" and self.level_num == 3:
            self.congestion = "畅通"
        elif self.level_num == 2 and (self.congestion == "轻度拥堵" or self.congestion == "中度拥堵"):
            self.congestion = "畅通"

        return self.congestion, average_density


class Congestion:
    def __init__(self, define, config_data):
        self.define = define
        self.speed_limits = config_data["SpeedLimit"]
        self.density_factor = config_data["DensityLimit"]
        self.level_num = int(config_data["congestion_level_num"])
        # 迟滞系数（可配置）
        self.hysteresis_factor = 5  # 退出阈值 = 进入阈值 + 5
        # 上一次的拥堵状态（初始为"畅通"）
        self.last_congestion = "畅通"
        # 拥堵等级及其严重程度排序
        self.CONGESTION_ORDER = ["严重拥堵", "中度拥堵", "轻度拥堵", "缓行", "畅通"]

    def run(self, data):
        # 提取基础数据
        lane_num = int(data["info"]["lane_num"])
        window_length = data["info"]["time_interval"]
        event_time = data["data"]["time"]

        # 获取车速阈值配置
        car_max_speed = data["info"]["car_max_speed"]
        speed_key = str(int(car_max_speed)) if car_max_speed >= 60 else "50"
        if speed_key not in self.speed_limits:
            speed_key = "80"
        speed_config = self.speed_limits[speed_key]

        # 计算平均速度
        type_speed_dict = data["data"]["type_speed_dict"]
        mean_speed = type_speed_dict.get("1", {"mean_speed": 80})["mean_speed"]

        # 计算总车流量和密度
        pass_num = sum(type_speed_dict.get(vtype, {"count": 0})["count"]
                       for vtype in type_speed_dict)
        interval_vlp = 0
        interval_keys = list(data["data"]["interval_dict"].keys())
        for key in reversed(interval_keys):
            if data["data"]["interval_dict"][key][self.define["TIME"]] > (event_time - window_length):
                interval_vlp += 1
            else:
                break

        try:
            time_factor = 3600 / window_length.total_seconds()
            average_density = int((pass_num + interval_vlp) * time_factor / mean_speed)
        except ZeroDivisionError:
            average_density = 0

        # 获取当前拥堵状态（使用进入阈值）
        current_congestion = self._get_congestion_level(mean_speed, average_density, speed_config, lane_num)

        # 应用非对称迟滞机制
        if current_congestion != self.last_congestion:
            # 判断变化方向：严重程度增加还是减少
            current_index = self.CONGESTION_ORDER.index(current_congestion)
            last_index = self.CONGESTION_ORDER.index(self.last_congestion)

            # 如果是状态改善（严重程度降低），应用额外的退出阈值
            if current_index < last_index:
                exit_thresholds = self._get_improved_exit_thresholds(speed_config)
                exit_congestion = self._get_congestion_level(mean_speed, average_density, exit_thresholds, lane_num)

                # 只有当基于退出阈值的判断也改变时，才更新状态
                if exit_congestion == current_congestion:
                    self.last_congestion = current_congestion
            else:
                # 状态恶化（严重程度增加），使用原始阈值
                self.last_congestion = current_congestion

        # 根据配置调整最终等级
        final_congestion = self._adjust_congestion_level(self.last_congestion, mean_speed, speed_config, lane_num, average_density)

        return final_congestion, average_density

    def _get_congestion_level(self, mean_speed, density, speed_config, lane_num):
        """根据速度和密度确定拥堵等级（使用进入阈值）"""
        if mean_speed >= speed_config["l1"] or density <= (20 * lane_num):
            return "畅通"
        elif mean_speed >= speed_config["l2"]:
            return "轻度拥堵"
        elif mean_speed >= speed_config["l3"]:
            return "中度拥堵"
        else:
            return "严重拥堵"

    def _get_improved_exit_thresholds(self, speed_config):
        """生成用于退出判断的阈值（比进入阈值更高）"""
        return {
            "l1": speed_config["l1"] + self.hysteresis_factor,
            "l2": speed_config["l2"] + self.hysteresis_factor,
            "l3": speed_config["l3"] + self.hysteresis_factor,
            "l0": speed_config["l0"] + self.hysteresis_factor,
        }

    def _adjust_congestion_level(self, congestion, mean_speed, speed_config, lane_num, density):
        """根据配置调整拥堵等级"""
        if congestion == "畅通" and self.level_num == 5:
            if mean_speed < speed_config["l0"] and density > (20 * lane_num):
                return "缓行"

        elif congestion == "轻度拥堵" and self.level_num == 3:
            return "畅通"

        elif self.level_num == 2 and congestion in ["轻度拥堵", "中度拥堵"]:
            return "畅通"

        return congestion


if __name__ == '__main__':
    print("111")

